package com.coocaa.x.service.litedb.data.client;

import android.os.RemoteException;

import com.alibaba.fastjson.JSONObject;
import com.coocaa.x.framework.utils.LogUtils;
import com.coocaa.x.service.XServiceManager;
import com.coocaa.x.service.litedb.data.common.LiteDBDefine;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * Created by C0der on 2015/3/11.
 */
public abstract class LiteDBSupport {
    private static final String TAG = "LiteDBSupport";
    private static final List<String> CREATED_TABLE = new ArrayList<String>();
    private String name = null;
    private Field[] fields = null;

    public LiteDBSupport(String name, int version) throws Exception {
        this.name = name;
        fields = getClass().getDeclaredFields();
        synchronized (CREATED_TABLE) {
            if (!CREATED_TABLE.contains(name)) {
                LinkedHashMap<String, String> kv = new LinkedHashMap<String, String>();
                for (Field field : fields) {// --for() begin
                    field.setAccessible(true);
                    String field_name = field.getName();
                    String field_type = field.getType().toString();
                    LogUtils.d("table", field_type + "  " + field_name);

                    try {
                        if (field_type.equals("class java.lang.String")) {
                            kv.put(field_name, LiteDBDefine.FILED_TYPE_STRING);
                        } else if (field_type.equals("long")) {
                            kv.put(field_name, LiteDBDefine.FILED_TYPE_LONG);
                        } else if (field_type.equals("double")) {
                            kv.put(field_name, LiteDBDefine.FILED_TYPE_REAL);
                        } else if (field_type.equals("int")) {
                            kv.put(field_name, LiteDBDefine.FILED_TYPE_INT);
                        } else if (field_type.equals("float")) {
                            kv.put(field_name, LiteDBDefine.FILED_TYPE_REAL);
                        } else if (field_type.equals("boolean")) {
                            kv.put(field_name, LiteDBDefine.FILED_TYPE_STRING);
                        }
                    } catch (Exception e) {
                        throw e;
                    }
                }
                try {
                    XServiceManager.getLiteDBService().createTable(name,
                            JSONObject.toJSONString(kv), version);
                    CREATED_TABLE.add(name);
                } catch (Exception e) {
                    throw e;
                }
            }
        }
    }

    public void insert() throws Exception {
        Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
        try {

            XServiceManager.getLiteDBService().insert(name, JSONObject.toJSONString(getFVMap()));
        } catch (Exception e) {
            throw e;
        }
    }

    public void updateAll() throws Exception {
        Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
        update("");
    }

    public void update(String where, String... args) throws Exception {
        Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
        List<String> _args = new ArrayList<String>();
        if (args != null) {
            for (String a : args)
                _args.add(a);
        }
        try {
            XServiceManager.getLiteDBService().update(name, JSONObject.toJSONString(getFVMap()),
                    where, _args);
        } catch (RemoteException e) {
            throw e;
        }
    }

    public void deleteAll() throws Exception {
        Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
        delete("");
    }

    public void delete(String where, String... args) throws Exception {
        Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
        List<String> _args = new ArrayList<String>();
        if (args != null) {
            for (String a : args)
                _args.add(a);
        }
        try {
            XServiceManager.getLiteDBService().delete(name, where, _args);
        } catch (RemoteException e) {
            throw e;
        }
    }

    public List<LiteDBSupport> selectAll() throws Exception {
        Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
        return select("", "", "", "");
    }

    public List<LiteDBSupport> select(String groupby, String having, String orderby, String where,
                                      String... args) throws Exception {
        Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
        List<String> _args = new ArrayList<String>();
        if (args != null) {
            for (String a : args)
                _args.add(a);
        }
        List<LiteDBSupport> ret = new ArrayList<LiteDBSupport>();
        List<String> _fields = new ArrayList<String>();
        for (Field field : fields)
            _fields.add(field.getName());
        long time2 = System.currentTimeMillis();
        try {
            List<String> result = XServiceManager.getLiteDBService().select(name, _fields, where,
                    _args, groupby, having, orderby);
            long time3 = System.currentTimeMillis();
            LogUtils.d(TAG, "select1 cost:" + (time3 - time2));
            if (result.size() > 0) {
                for (String string : result) {
                    LinkedHashMap<String, String> map = JSONObject.parseObject(string,
                            LinkedHashMap.class);
                    long time4 = System.currentTimeMillis();
                    // LiteDBSupport obj = form(map);
                    LiteDBSupport obj = (LiteDBSupport) getClass().newInstance();
                    for (Field field : fields) {
                        String field_type = field.getType().toString();
                        String val = map.get(field.getName());
                        if (field_type.equals("class java.lang.String")) {
                            field.set(obj, val);
                        } else if (field_type.equals("long")) {
                            field.set(obj, Long.valueOf(val));
                        } else if (field_type.equals("double")) {
                            field.set(obj, Double.valueOf(val));
                        } else if (field_type.equals("int")) {
                            field.set(obj, Integer.valueOf(val));
                        } else if (field_type.equals("float")) {
                            field.set(obj, Float.valueOf(val));
                        } else if (field_type.equals("boolean")) {
                            field.set(obj, Boolean.valueOf(val));
                        }
                    }
                    LogUtils.d(TAG, "selectXX cost:" + (System.currentTimeMillis() - time4));
                    ret.add(obj);
                }
                long time4 = System.currentTimeMillis();
                LogUtils.d(TAG, "select2 cost:" + (time4 - time3));
            }
        } catch (RemoteException e) {
            throw e;
        }
        return ret;
    }

    private LinkedHashMap<String, String> getFVMap() {
        LinkedHashMap<String, String> kv = new LinkedHashMap<String, String>();
        try {
            for (Field field : fields) {
                String field_name = field.getName();
                String field_value = String.valueOf(field.get(this));
                kv.put(field_name, field_value);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return kv;
    }

    // protected abstract LiteDBSupport form(Map<String, String> kv);
}
